home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Freaks Macintosh Archive
/
Freaks Macintosh Archive.bin
/
Freaks Macintosh Archives
/
Mp3
/
MPEGAudioPlayerSource.cpt
/
map
/
maplay.cc
< prev
next >
Wrap
Text File
|
1994-11-16
|
13KB
|
447 lines
/*
* @(#) maplay.cc 1.20, last edit: 6/22/94 12:32:55
* @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
* @(#) Berlin University of Technology
*
* Many thanks for ideas and implementations to:
* -> Jim Boucher (jboucher@flash.bu.edu)
* for his idea and first implementation of 8 kHz u-law output
* -> Louis P. Kruger (lpkruger@phoenix.princeton.edu)
* for his implementation of the LinuxObuffer class
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Changes from version 1.1 to 1.2:
* - minor changes to create a LinuxObuffer object
* - minor changes for a u-law version, which creates 8 kHz u-law output
* on an amd device or in stdout mode, if compiled with ULAW defined
* - option -amd forces maplay to treat /dev/audio as an amd device
* in the u-law version. This is helpful on some SPARC clones.
* - iostreams manipulator calls like "cerr << setw (2) << ..." replaced by
* "cerr.width (2); ..." due to problems with older GNU C++ releases.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream.h>
//#include <iomanip.h>
#include "all.h"
#include "crc.h"
#include "header.h"
#include "ibitstream.h"
#include "obuffer.h"
#include "subband.h"
#include "subband_layer_1.h"
#include "subband_layer_2.h"
#include "synthesis_filter.h"
// data extracted from commandline arguments:
static bool verbose_mode = False, filter_check = False;
static bool stdout_mode = False;
static enum e_channels which_channels = bothC;
static bool use_speaker = False, use_headphone = False, use_line_out = False;
#ifdef ULAW
static bool force_amd = False;
#endif
static bool use_own_scalefactor = False;
static real scalefactor;
// data extracted from header of first frame:
static uint32 layer;
static e_mode mode;
static e_sample_frequency sample_frequency;
// objects needed for playing a file:
static Ibitstream *stream;
static Header *header;
static Crc16 *crc;
static Subband *subbands[32];
static SynthesisFilter *filter1 = NULL, *filter2 = NULL;
static Obuffer *buffer = NULL;
static void Exit (int returncode)
// delete some objects and exit
{
delete buffer; // delete on NULL-pointers are harmless
delete filter1;
delete filter2;
delete header;
delete stream;
exit (returncode);
}
main2 (int argc, char *argv[], short refNums[])
{
int i;
if (argc < 2 || !strncmp (argv[1], "-h", 2))
{
usage:
cerr << "\nusage: " << argv[0]
<< " [-v] [-s] [-l] [-r] "
"[-c] [-f ushort] filename\n"
" filename filename of a MPEG audio stream or - for stdin\n"
" -v verbose mode\n"
" -s write pcm samples to stdout\n"
" -l decode only the left channel\n"
" -r decode only the right channel\n"
#ifdef ULAW
" -amd force maplay to treat /dev/audio as an amd device\n"
#endif
" -c check for filter range violations\n"
" -f ushort use this scalefactor instead of the default value 32768\n\n"
"@(#) MPEG Audio Player maplay 1.2 "
#ifdef ULAW
"(8 kHz u-law "
#else
"("
#endif
"Macintosh"
" version)\n"
"@(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)\n"
"@(#) Berlin University of Technology\n"
"@(#) Created: 6/23/94 14:12:46\n"
"@(#) This program is free software. See the GNU General Public License\n"
"@(#) in the file COPYING for more details.\n\n";
exit (0);
}
// parse arguments:
for (i = 1; i < argc; ++i)
if (argv[i][0] == '-' && argv[i][1])
switch ((int)argv[i][1])
{
case 'v':
verbose_mode = True;
break;
case 's':
stdout_mode = True;
break;
case 'l':
which_channels = leftC;
break;
case 'r':
which_channels = rightC;
break;
#ifdef MAC
case 'm':
use_speaker = True;
break;
#endif
#ifdef ULAW
case 'a':
force_amd = True;
break;
#endif
case 'c':
filter_check = True;
break;
case 'f':
if (++i == argc)
{
cerr << "please specify a new scalefactor after the -f option!\n";
exit (1);
}
use_own_scalefactor = True;
sscanf (argv[i], "%f", &scalefactor);
break;
default:
goto usage;
}
else
goto usage;
if (!(use_speaker || use_headphone || use_line_out))
use_speaker = True;
stream = new Ibitstream (refNums[0]); // read from file
header = new Header;
if (!header->read_header (stream, &crc))
{
cerr << "no header found!\n";
Exit (1);
}
// get info from header of first frame:
layer = header->layer ();
if ((mode = header->mode ()) == single_channel)
which_channels = leftC;
sample_frequency = header->sample_frequency ();
return (which_channels == bothC) + 1;
}
void play_file(short refNums[])
{
int i;
bool read_ready = False, write_ready = False;
// create filter(s):
#ifdef ULAW
if (use_own_scalefactor)
filter1 = new SynthesisFilter (0, sample_frequency, scalefactor);
else
filter1 = new SynthesisFilter (0, sample_frequency);
if (mode != single_channel && which_channels == bothC)
if (use_own_scalefactor)
filter2 = new SynthesisFilter (1, sample_frequency, scalefactor);
else
filter2 = new SynthesisFilter (1, sample_frequency);
#else
if (use_own_scalefactor)
filter1 = new SynthesisFilter (0, scalefactor);
else
filter1 = new SynthesisFilter (0);
if (mode != single_channel && which_channels == bothC)
if (use_own_scalefactor)
filter2 = new SynthesisFilter (1, scalefactor);
else
filter2 = new SynthesisFilter (1);
#endif // !ULAW
// create buffer:
if (stdout_mode)
if (mode == single_channel || which_channels != bothC)
buffer = new FileObuffer (1);
else
buffer = new FileObuffer (2);
else
#ifdef MAC
{
if (MacObuffer::class_suitable (mode == single_channel || which_channels != bothC) ? 1 : 2)
if (mode == single_channel || which_channels != bothC)
buffer = new MacObuffer (1, header); // mono
else
buffer = new MacObuffer (2, header); // stereo
}
#else
{
cerr << "Sorry, I don't know your audio device.\n"
"Please use the stdout mode.\n";
Exit (0);
}
#endif // !MAC
#ifdef MAC
if (stdout_mode)
#endif
if (verbose_mode)
{
// print informations about the stream
cerr << "File is a layer " << header->layer_string () << ' '
<< header->mode_string () << " MPEG audio stream with";
if (!header->checksums ())
cerr << "out";
cerr << " checksums.\nThe sample frequency is "
<< header->sample_frequency_string () << " at a bitrate of "
<< header->bitrate_string () << ".\n"
"This stream is ";
if (header->original ())
cerr << "an original";
else
cerr << "a copy";
cerr << " and is ";
if (!header->copyright ())
cerr << "not ";
cerr << "copyright protected.\n";
}
do
{
// is there a change in important parameters?
// (bitrate switching is allowed)
if (header->layer () != layer)
{
// layer switching is allowed
if (verbose_mode)
cerr << "switching to layer " << header->layer_string () << ".\n";
layer = header->layer ();
}
if ((mode == single_channel && header->mode () != single_channel) ||
(mode != single_channel && header->mode () == single_channel))
{
// switching from single channel to stereo or vice versa is not allowed
cerr << "illegal switch from single channel to stereo or vice versa!\n";
Exit (1);
}
if (header->sample_frequency () != sample_frequency)
{
// switching the sample frequency is not allowed
cerr << "sorry, can't switch the sample frequency in the middle of the stream!\n";
Exit (1);
}
// create subband objects:
if (header->layer () == 1)
{
if (header->mode () == single_channel)
for (i = 0; i < header->number_of_subbands (); ++i)
subbands[i] = new SubbandLayer1 (i);
else if (header->mode () == joint_stereo)
{
for (i = 0; i < header->intensity_stereo_bound (); ++i)
subbands[i] = new SubbandLayer1Stereo (i);
for (; i < header->number_of_subbands (); ++i)
subbands[i] = new SubbandLayer1IntensityStereo (i);
}
else
for (i = 0; i < header->number_of_subbands (); ++i)
subbands[i] = new SubbandLayer1Stereo (i);
}
else if (header->layer () == 2)
{
if (header->mode () == single_channel)
for (i = 0; i < header->number_of_subbands (); ++i)
subbands[i] = new SubbandLayer2 (i);
else if (header->mode () == joint_stereo)
{
for (i = 0; i < header->intensity_stereo_bound (); ++i)
subbands[i] = new SubbandLayer2Stereo (i);
for (; i < header->number_of_subbands (); ++i)
subbands[i] = new SubbandLayer2IntensityStereo (i);
}
else
for (i = 0; i < header->number_of_subbands (); ++i)
subbands[i] = new SubbandLayer2Stereo (i);
}
else
{
cerr << "sorry, layer 3 not implemented!\n";
Exit (0);
}
// start to read audio data:
for (i = 0; i < header->number_of_subbands (); ++i)
subbands[i]->read_allocation (stream, header, crc);
if (header->layer () == 2)
for (i = 0; i < header->number_of_subbands (); ++i)
((SubbandLayer2 *)subbands[i])->read_scalefactor_selection (stream, crc);
if (!crc || header->checksum_ok ())
{
// no checksums or checksum ok, continue reading from stream:
for (i = 0; i < header->number_of_subbands (); ++i)
subbands[i]->read_scalefactor (stream, header);
do
{
for (i = 0; i < header->number_of_subbands (); ++i)
read_ready = subbands[i]->read_sampledata (stream);
do
{
for (i = 0; i < header->number_of_subbands (); ++i)
write_ready = subbands[i]->put_next_sample (which_channels, filter1, filter2);
filter1->calculate_pcm_samples (buffer);
if (which_channels == bothC && header->mode () != single_channel)
filter2->calculate_pcm_samples (buffer);
}
while (!write_ready);
}
while (!read_ready);
buffer->write_buffer (refNums[1]); // write to stdout
if (buffer->abort()) break;
}
else
// Sh*t! Wrong crc checksum in frame!
cerr << "WARNING: frame contains wrong crc checksum! (throwing frame away)\n";
for (i = 0; i < header->number_of_subbands (); ++i)
delete subbands[i];
}
while (header->read_header (stream, &crc));
delete buffer;
#ifdef MAC
}
short post_process(void)
{
uint32 range_violations = filter1->violations ();
if (mode != single_channel && which_channels == bothC)
range_violations += filter2->violations ();
if (!stdout_mode && verbose_mode)
{
// print informations about the stream
cerr << "File is a layer " << header->layer_string () << ' '
<< header->mode_string () << " MPEG audio stream with";
if (!header->checksums ())
cerr << "out";
cerr << " checksums.\nThe sample frequency is "
<< header->sample_frequency_string () << " at a bitrate of "
<< header->bitrate_string () << ".\n"
"This stream is ";
if (header->original ())
cerr << "an original";
else
cerr << "a copy";
cerr << " and is ";
if (!header->copyright ())
cerr << "not ";
cerr << "copyright protected.\n";
}
#endif
if (filter_check)
{
// check whether (one of) the filter(s) produced values not in [-1.0, 1.0]:
if (range_violations)
{
cerr << range_violations << " range violations have occured!\n";
if (stdout_mode)
cerr << "If you notice these violations,\n";
else
cerr << "If you have noticed these violations,\n";
cerr << "please use the -f option with the value ";
if (mode != single_channel && which_channels == bothC &&
filter2->hardest_violation () > filter1->hardest_violation ())
cerr << filter2->recommended_scalefactor ();
else
cerr << filter1->recommended_scalefactor ();
cerr << "\nor a greater value up to 32768 and try again.\n";
}
}
if (verbose_mode)
{
// print playtime of stream:
real playtime = filter1->seconds_played (Header::frequency (sample_frequency));
uint32 minutes = (uint32)(playtime / 60.0);
uint32 seconds = (uint32)playtime - minutes * 60;
uint32 centiseconds = (uint32)((playtime - (real)(minutes * 60) - (real)seconds) * 100.0);
cerr << "end of stream, playtime: " << minutes << ':';
cerr.width (2);
cerr.fill ('0');
cerr << seconds << '.';
cerr.width (2);
cerr.fill ('0');
cerr << centiseconds << '\n';
}
return mode;
}